#!/usr/bin/env python3


from List import List
from Dir_tree import *

from pythonic_c_release import *


import os

def copy_c(src_dir, dst_dir, name): copy_file(src_dir, dst_dir, name+".c")
def copy_h(src_dir, dst_dir, name): copy_file(src_dir, dst_dir, name+".h")

def copy_file(src_dir, dst_dir, f_name):
    import os
    src_file = (src_dir/f_name).path()
    dst_file = (dst_dir/f_name).path()
    os.system("cp {src_file} {dst_file}".format(**locals()))

def copy_dir(src_dir, dst_dir): copy_file(src_dir+"/*", dst_dir+"/*")




#def div_c(src_name, code_name, test_name):
def div_c(src_dir, dst_code_dir, dst_test_dir, name, test_all_file, ut_rely_list):
    #cur_dir = Dir_tree()
    test_name = name+"_unit_test"
    src_file = src_dir/(name+".c")
    code_file = dst_code_dir/(name+".c")
    test_file = dst_test_dir/(test_name+".c")
    
    class_name = name

    src_list = list(src_file)


    code_list = []
    test_list = []


    def get_func_name(line):
        if "__" in line and "(" in line and ")" in line and ";" not in line:
            func_name = line.split("(", 1)[0].rsplit(" ", 1)[1].strip()
            return func_name
        else:
            return None

    test_func_list = []

    cur_list = code_list
    for line in src_list:
        func_name = get_func_name(line)
        if func_name != None:
            if "unit_test" in func_name:
                #print("switch unit_test <{func_name}>".format(**locals()))
                cur_list = test_list
                test_func_list.append(func_name)
            else:
                #print("switch code      <{func_name}>".format(**locals()))
                cur_list = code_list
        cur_list.append(line)

    code_file << code_list

    include_head = """
#include <{class_name}.h>
""".format(**locals())
    guard_pre = """
#ifndef _UT__{class_name}__UT_
#define _UT__{class_name}__UT_
""".format(**locals())
    guard_follow = """
#endif//_UT__{class_name}__UT_
""".format(**locals())


    #test_list = [guard_pre, ] + test_list + [guard_follow, ]


    test_func_list = (";\n"+" "*4).join([ "{func_name}(&error_flag)".format(**locals()) for func_name in test_func_list ])
    test_file << ""
    test_file + include_head
    # 如果是非测试类， 增加测试代码
    # 测试类的代码只在test_all_file里面存储一份。
    if name not in ut_rely_list:
        test_file + test_list
    # 
    test_all_file + test_list

    test_file + r"""
int main()
{{
    void* error_flag = NULL;
    {test_func_list};
    if (error_flag != NULL){{
        DsExceptionPrintStack(&error_flag);
        printf("Error!\n");
    }}
        
}}

""".format(**locals())
    from white_wash_c import wash_c
    
    wash_c(".."/code_file, ".."/code_file, name)
    wash_c(".."/test_file, ".."/test_file, test_name)
    
    


# 把头文件里面的单元测试接口全部清除。
def filter_h(src_dir, dst_dir, h_name, test_all_file):
    unit_test_func_list = []

    src_h = src_dir/(h_name+".h")
    dst_h = dst_dir/(h_name+".h")
    # src_h_code_list = list(src_h)

    code_list = []
    #for line in src_h_code_list:
    for line in list(src_h):
        if "__unit_test" in line:
            unit_test_func_list.append(line)
            continue
        code_list.append(line)
    dst_h << code_list

    from white_wash_h import wash_h
    wash_h(".."/dst_h, ".."/dst_h, h_name)

    test_all_file + ("""#include <{h_name}.h>""".format(**locals()) )
    test_all_file + unit_test_func_list



def make_compile_file(depend_dict):
    prev = """
module=$1

case ${module} in
"""
# "Array") depends="___ut.c Memory.c Ds_math.c Ds_exception.c";;
# "Ds_math") depends="Ds_exception.c";;
# "___ut") depends="Memory.c Ds_math.c Ds_exception.c";;
# "Memory") depends="Ds_math.c Ds_exception.c";;
    depends_list = []
    for module_name in depend_dict:
        depends = depend_dict[module_name]
        depends_str = " ".join( ["{depend}.c".format(**locals()) for depend in depends if depend != module_name] )
        depend_line = '''"{module_name}") depends="{depends_str}";;'''.format(**locals())
        depends_list.append(depend_line)
    depends_list_str = "\n".join(depends_list)

    follow = """

*) {
    echo "==[No Such Module]=="; 
    echo "usage:"
    echo "    $0 <module_name>"
    echo ""
    exit 1
};;
esac


compile_module(){
    ext_c="../src_ext/rdps_log.c ../src_ext/buffer.c"
    inc="-I../inc -I../inc_ext"
    mysql="-I/usr/include/mysql -lmysqlclient"
    libs="-lpthread -lm"
    debug="-g"
    target_file="-o ../a.out"
    rest="${ext_c} ${inc} ${mysql} ${libs} ${debug} ${target_file}"


    gcc="gcc ../src_unit_test/${module}_unit_test.c ${module}.c ${depends} ${rest}"

    echo ""
    echo "cd src"
    echo ${gcc}
    echo ""

    cd src
    ${gcc}
    
    echo "finish"
}

compile_module
"""
    return prev + depends_list_str + follow




output_dir = Dir_tree()/"c_code"
out_src_dir = output_dir/"src"
out_src_ext_dir = output_dir/"src_ext"
out_inc_dir = output_dir/"inc"
out_inc_ext_dir = output_dir/"inc_ext"
out_test_dir = output_dir/"src_unit_test"


out_src_dir.rm()
out_src_ext_dir.rm()
out_inc_dir.rm()
out_inc_ext_dir.rm()
out_test_dir.rm()
test_all_h = out_test_dir/"unit_test_all.h"
test_all_c = out_test_dir/"unit_test_all.c"
test_all_c << "#include <unit_test_all.h>"

out_rely_file = output_dir/"module_list.rely"
out_compile_file = output_dir/"compile.sh"

inc_common_dir = Dir_tree()/"1_inc_common"
inc_dir = Dir_tree()/"2_inc"
src_dir = Dir_tree()/"3_src"

import sys
top_module_name = sys.argv[1]

depends_dict = {}
for line in list(out_rely_file):
    #print(line)
    module_name = line.split("<", 1)[1].split(">", 1)[0].strip()
    module_rely_list = eval( line.split(">", 1)[1] )
    depends_dict[module_name] = module_rely_list
# add unit_test_all rely
ut_rely_list = [top_module_name, ]
for module_name in ut_rely_list:
    depends_dict[module_name].append("unit_test_all")

compile_code = make_compile_file(depends_dict)

out_compile_file << compile_code



#name_list = ["Array", "Ds_exception", "Memory", "Ds_math", "___ut"]
name_list = [m for m in depends_dict[top_module_name] if m != "unit_test_all" ]
print("="*40)
# for f in src_dir.glob("*"):
#     #print(f.path())
#     module_name = f.path().rsplit("/", 1)[1].rsplit(".", 1)[0].strip()
#     if module_name not in name_list:
#         name_list.append(module_name)

print(name_list)

for name in name_list:
    pass
    filter_h(inc_dir, out_inc_dir, name, test_all_h)

for name in name_list:
    #if "main" not in name:
    div_c(src_dir, out_src_dir, out_test_dir, name, test_all_c, ut_rely_list)
    
for name in ["ds_base", "ds_base_tuple", "ds_util", "rdps_log", "buffer"]:
    copy_h(inc_common_dir, out_inc_ext_dir, name)
    

for name in ["rdps_log", "buffer"]:
    copy_c(inc_common_dir, out_src_ext_dir, name)

copy_h(out_test_dir, out_inc_dir, "unit_test_all")
copy_c(out_test_dir, out_src_dir, "unit_test_all")

out_rely_file.rm()